package edu.jxufe.nb112.common.security.shiro;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ShiroRedisCacheManager implements CacheManager {

    private static final Logger LOG = LoggerFactory.getLogger(ShiroRedisCacheManager.class.getName());

    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();

    private Map<String, Long> expires;

    private RedisTemplate redisTemplate;

    //缓存中的key前缀由keyPrefix+':'+cacheName+':'
    private String keyPrefix = "shiro_cache";

    //全局缓存过期时间
    private Long globalExpiration= 0L;

    public ShiroRedisCacheManager(RedisTemplate redisTemplate) {
        this.redisTemplate=redisTemplate;
    }

    /**
     * 创建缓存实例
     * @param cacheName 缓存名称
     * @param expiration 过期时间 0不过期
     * @param <K>
     * @param <V>
     * @return
     */
    protected <K, V> Cache<K, V> createCache(String cacheName,Long expiration){
        if (LOG.isDebugEnabled()) {
            LOG.debug("RedisShiroCacheManager创建名称为{}的ShiroRedisCache实例，过期：{}",cacheName,expiration);
        }
        Cache cache = new ShiroRedisCache<K, V>(cacheName, keyPrefix,redisTemplate,expiration==null?0L:expiration);
        return cache;
    }

    /**
     * 获取缓存，没有将创建
     * @param cacheName
     * @param <K>
     * @param <V>
     * @return
     * @throws CacheException
     */
    public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
       if (LOG.isDebugEnabled()) {
            LOG.debug("RedisShiroCacheManager获取名称为{}的ShiroRedisCache实例",cacheName);
       }
        Cache cache = caches.get(cacheName);
        if (cache == null) {
            Long expire = globalExpiration;
            if(expires!=null){
                Long exp = expires.get(cacheName);
                if(exp!=null && exp.longValue()>0){
                    expire=exp;
                }
            }
            cache = createCache(cacheName,expire);
            caches.put(cacheName, cache);
        }
        return cache;
    }

    public void setExpires(Map<String, Long> expires) {
        this.expires = (expires != null ? new ConcurrentHashMap<String, Long>(expires) : null);
    }
    public Map<String, Long> getExpires() {
        return expires;
    }
    public String getKeyPrefix() {
        return this.keyPrefix;
    }

    public void setKeyPrefix(String keyPrefix) {
        this.keyPrefix = keyPrefix;
    }

    public Long getGlobalExpiration() {
        return globalExpiration;
    }

    public void setGlobalExpiration(Long globalExpiration) {
        this.globalExpiration = globalExpiration;
    }
}
